package com.tuniu.agents.evaluators.common;

import com.tuniu.agents.advisor.ChatEnvironmentMemory;
import com.tuniu.agents.agent.Agent;
import com.tuniu.agents.agent.AgentManager;
import com.tuniu.agents.common.service.AntispamService;
import com.tuniu.agents.evaluator.EvaluationResult;
import com.tuniu.agents.evaluator.IEvaluator;
import com.tuniu.agents.memory.MemoryManager;
import com.tuniu.agents.message.MessageSender;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.Map;
import java.util.UUID;

/**
 * Abstract evaluator base class
 * Implements common evaluator logic
 */
@Component
@Slf4j
public abstract class AbstractEvaluator<T> implements IEvaluator<T> {

    protected static final String EVALUATOR_RESULT = "evaluator_result"; // Evaluation result
    protected static final String EVALUATOR_IDS = "evaluator_ids"; // Snapshot IDs included in evaluation

    /**
     * Evaluator name
     */
    private final String name;
    /**
     * Evaluator description
     */
    private final String description;

    @Autowired
    protected AgentManager agentManager;

    @Autowired
    protected ChatEnvironmentMemory chatEnvironmentMemory;

    @Autowired
    protected MemoryManager memoryManager;

    @Autowired
    private AntispamService antispamService;

    @Autowired
    protected MessageSender messageSender;

    /**
     * Evaluator Agent
     */
    protected Agent agent;


    protected AbstractEvaluator(String name, String description) {
        this.name = name;
        this.description = description;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public String getDescription() {
        return description;
    }


    @Override
    public EvaluationResult evaluate(String userId) {
        String conversationId = UUID.randomUUID().toString();
        T target = preEvaluate(userId, conversationId);

        if (!supports(target)) {

            return EvaluationResult.Builder.newBuilder()
                    .evaluatorName(getName())
                    .success(true)
                    .message("evaluator success")
                    .build();
        }

        try {
            return doEvaluate(target);
        } catch (Exception e) {
            log.error("Evaluation failed: {}", e.getMessage());
            return EvaluationResult.Builder.newBuilder()
                    .evaluatorName(getName())
                    .success(false)
                    .message("Evaluation failed")
                    .build();
        }
    }

    /**
     * Check if re-evaluation is needed
     *
     * @param userId
     * @param target
     */
    protected abstract String checkEvaluateResult(String userId, T target);

    @Override
    public Flux<String> evaluateFlux(String userId) {
        String conversationId = UUID.randomUUID().toString();
        T target = preEvaluateByUserId(userId, conversationId);

        String lastEvaluateResult = checkEvaluateResult(userId, target); // Check if evaluation result has changed
        if (lastEvaluateResult != null) {
            return Flux.just(lastEvaluateResult);
        }
        if (!supports(target)) {
            log.error("Evaluation failed not support: {}", target);
            return Flux.empty();
        }
        try {
            String customMessage = "";
            StringBuilder fullReslt = new StringBuilder();
            return doEvaluateFlux(target)
                    .map(chunk -> {
                        fullReslt.append(chunk);
                        return chunk;
                    })
                    .concatWith(Mono.just(customMessage)
                            .map(stopContent -> this.checkAntispam(userId, conversationId, null, fullReslt.append(customMessage).toString())));

        } catch (Exception e) {
            log.error("Evaluation failed: {}", e.getMessage());
            return Flux.empty();
        }
    }

    public String checkAntispam(String userId, String conversationId, String responseId, String fullResult) {
        try {
            log.info("Favorites evaluation model result: {}", fullResult);
            if (org.apache.commons.lang3.StringUtils.isEmpty(antispamService.antispamCheck(conversationId, fullResult, responseId))) {
                // Validation passed
                afterEvaluate(userId, fullResult);
                return "";
            } else {
                return "STOP";
            }
        } catch (Exception e) {
            log.error("Favorites evaluator antispam word check failed", e);
            return "STOP";
        }
    }


    /**
     * Execute specific evaluation logic
     *
     * @param target Evaluation target
     * @return Evaluation result
     */
    protected abstract EvaluationResult doEvaluate(T target);

    protected abstract Flux<String> doEvaluateFlux(T target);

    /**
     * Pre-process data
     * Get data from interface or database
     *
     * @param conversationId Conversation ID
     * @param queryId Query ID
     * @return Shopping cart
     */
    protected abstract T preEvaluate(String conversationId, String queryId);

    protected abstract T preEvaluateByUserId(String userId, String conversationId);

    protected void afterEvaluate(String userId, String result) {
        // Save evaluation result
        chatEnvironmentMemory.add(userId, Map.of(EVALUATOR_RESULT, result));
    }

    /**
     * Get evaluator Agent
     *
     * @return Evaluator Agent
     */
    protected abstract void getAgent();

    /**
     * MD5 encryption for string
     *
     * @param str
     * @return
     */
    protected String md5(String str) {
        try {
            return DigestUtils.md5Hex(str.getBytes("UTF-8"));
        } catch (Exception e) {
            log.error("MD5 encryption failed: {}", e.getMessage());
            return null;
        }
    }

} 